package cn.wolfcode.shiro;

import cn.wolfcode.domain.Employee;
import cn.wolfcode.domain.Role;
import cn.wolfcode.exception.LogicException;
import cn.wolfcode.service.IEmployeeService;
import cn.wolfcode.service.IPermissionService;
import cn.wolfcode.service.IRoleService;
import cn.wolfcode.util.UserContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.print.DocFlavor;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义数据源
 */
@Component
public class CRMRealm extends AuthorizingRealm {

    @Autowired
    private IEmployeeService employeeService;
    @Autowired
    private IPermissionService permissionService;
    @Autowired
    private IRoleService roleService;

   @Autowired
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }


    /**
     * 提供授权信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取当前登录的员工的对象,获取员工id
        Employee currentUser = UserContext.getCurrentUser();
        Long empId = currentUser.getId();
        //查询数据库该员工的拥有的角色和权限数据

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if (!currentUser.isAdmin()){//判断是否是管理员,不是就查询

            List<String> expressions = permissionService.selectById(empId);
            info.addStringPermissions(expressions);//设置权限数据

            List<String> sns = roleService.selectSnById(empId);
            info.addRoles(sns);//设置角色数据
        }else {
            //权限拦截的功能是由shiro来做,不知道员工属性哪个是管理员,还是根据权限来判断,给通配符
            info.addStringPermission("*:*");
            info.addRole("admin");
        }

        //设置当前登录用户的拥有的角色和权限数据
        //info.addRoles(Arrays.asList("hr","seller"));
        return info;
    }

    /**
     * 提供认证信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //当前方法如果直接返回null,shiro会自动抛出账号不存在的异常
        //如果返回的结果不为null,shiro会自动从返回的对象中获取到真实的密码,再与token去对比

        //1.获取令牌中的用户名(前端传过来的)
        String username = (String)token.getPrincipal();
        /*UsernamePasswordToken usernamePasswordToken =(UsernamePasswordToken) token;
        usernamePasswordToken.getUsername();*/
        //2.查询数据库中是否存在该员工
        Employee employee = employeeService.selectByName(username);

        //3.不存在,就直接返回null
        if (employee!=null){
            if (employee.isStatus()!=true){
                throw new DisabledAccountException("账号已被禁用,请联系管理员");

            }
            //4如果存在,返回SimpleAuthenticationInfo对象
            //身份信息可以在任意地方获取,用来跟主体subject绑定在一起
            //在项目中就直接传入员工对象,主体subject绑定在一起,方便我们后续在任意地方获取当前登录员工对象
            //传入真实的密码,shiro会自动判断是否正确
            //传入当前数据源的名字,对我们现在的项目没有作用,一般是一个项目中有多个数据源时,需要做标志,该数据是从哪个数据源查的

            //第三个参数可以指定加密时的盐

            return new SimpleAuthenticationInfo(employee,employee.getPassword(),ByteSource.Util.bytes(username),this.getName());

        }
        return null;
    }
}
